const std = @import("std");
const builtin = @import("builtin");

const jetzig = @import("jetzig");
const zmd = @import("zmd");

pub const routes = @import("routes");
pub const static = @import("static");

// Override default settings in `jetzig.config` here:
pub const jetzig_options = struct {
    /// Middleware chain. Add any custom middleware here, or use middleware provided in
    /// `jetzig.middleware` (e.g. `jetzig.middleware.HtmxMiddleware`).
    pub const middleware: []const type = &.{
        // jetzig.middleware.HtmxMiddleware,
        // jetzig.middleware.CompressionMiddleware,
        // @import("app/middleware/DemoMiddleware.zig"),
    };

    // 请求体最大字节数
    // Maximum bytes to allow in request body.
    // pub const max_bytes_request_body: usize = std.math.pow(usize, 2, 16);
    pub const max_bytes_request_body: usize = 1048576; // 1MB

    // public目录支持最大字节数
    // Maximum filesize for `public/` content.
    // pub const max_bytes_public_content: usize = std.math.pow(usize, 2, 20);
    pub const max_bytes_public_content: usize = 5242880; // 5兆(5MB)

    // static目录支持最大字节数
    // Maximum filesize for `static/` content (applies only to apps using `jetzig.http.StaticRequest`).
    // pub const max_bytes_static_content: usize = std.math.pow(usize, 2, 18);
    pub const max_bytes_static_content: usize = 5242880; // 5兆(5MB);

    // 请求头名称最大长度
    // Maximum length of a header name. There is no limit imposed by the HTTP specification but
    // AWS load balancers reference 40 as a limit so we use that as a baseline:
    // https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_HttpHeaderConditionConfig.html
    // This can be increased if needed.
    // pub const max_bytes_header_name: u16 = 40;
    pub const max_bytes_header_name: u16 = 255;

    // form表单最大字段数量
    /// Maximum number of `multipart/form-data`-encoded fields to accept per request.
    // pub const max_multipart_form_fields: usize = 20;
    pub const max_multipart_form_fields: usize = 50;

    // Log message buffer size. Log messages exceeding this size spill to heap with degraded
    // performance. Log messages should aim to fit in the message buffer.
    pub const log_message_buffer_len: usize = 4096;

    // Maximum log pool size. When a log buffer is no longer required it is returned to a pool
    // for recycling. When logging i/o is slow, a high volume of requests will result in this
    // pool growing. When the pool size reaches the maximum value defined here, log events are
    // freed instead of recycled.
    pub const max_log_pool_len: usize = 256;

    // Number of request threads. Defaults to number of detected CPUs.
    // pub const thread_count: ?u16 = null;
    pub const thread_count: ?u16 = 8;

    // Number of response worker threads.
    // pub const worker_count: u16 = 4;
    pub const worker_count: u16 = 8;

    // Total number of connections managed by worker threads.
    // pub const max_connections: u16 = 512;
    pub const max_connections: u16 = 1024;

    // Per-thread stack memory to use before spilling into request arena (possibly with allocations).
    // pub const buffer_size: usize = 64 * 1024;
    pub const buffer_size: usize = 255 * 1024;

    // The size of each item in the available memory pool used by requests for rendering.
    // Total retained allocation: `worker_count * max_connections`.
    pub const arena_size: usize = 1024 * 1024;

    // Path relative to cwd() to serve public content from. Symlinks are not followed.
    pub const public_content_path = "public";

    // HTTP buffer. Must be large enough to store all headers. This should typically not be modified.
    // pub const http_buffer_size: usize = std.math.pow(usize, 2, 16);
    pub const http_buffer_size: usize = 1048576; // 1MB

    // The number of worker threads to spawn on startup for processing Jobs (NOT the number of
    // HTTP server worker threads).
    // pub const job_worker_threads: usize = 4;
    pub const job_worker_threads: usize = 8;

    // Duration before looking for more Jobs when the queue is found to be empty, in
    // milliseconds.
    pub const job_worker_sleep_interval_ms: usize = 10;

    /// Database Schema. Set to `@import("Schema")` to load `src/app/database/Schema.zig`.
    // pub const Schema = @import("Schema");

    /// HTTP cookie configuration
    pub const cookies: jetzig.http.Cookies.CookieOptions = .{
        .domain = switch (jetzig.environment) {
            .development => "localhost",
            .testing => "localhost",
            .production => "www.example.com",
        },
        .path = "/",
    };

    /// Key-value store options. Set backend to `.file` to use a file-based store.
    /// When using `.file` backend, you must also set `.file_options`.
    /// The key-value store is exposed as `request.store` in views and is also available in as
    /// `env.store` in all jobs/mailers.
    pub const store: jetzig.kv.Store.KVOptions = .{
        .backend = .memory,
        // .backend = .file,
        // .file_options = .{
        //     .path = "/path/to/jetkv-store.db",
        //     .truncate = false, // Set to `true` to clear the store on each server launch.
        //     .address_space_size = jetzig.jetkv.JetKV.FileBackend.addressSpace(4096),
        // },
    };

    /// Job queue options. Identical to `store` options, but allows using different
    /// backends (e.g. `.memory` for key-value store, `.file` for jobs queue.
    /// The job queue is managed internally by Jetzig.
    pub const job_queue: jetzig.kv.Store.KVOptions = .{
        .backend = .memory,
        // .backend = .file,
        // .file_options = .{
        //     .path = "/path/to/jetkv-queue.db",
        //     .truncate = false, // Set to `true` to clear the store on each server launch.
        //     .address_space_size = jetzig.jetkv.JetKV.FileBackend.addressSpace(4096),
        // },
    };

    /// Cache options. Identical to `store` options, but allows using different
    /// backends (e.g. `.memory` for key-value store, `.file` for cache.
    pub const cache: jetzig.kv.Store.KVOptions = .{
        .backend = .memory,
        // .backend = .file,
        // .file_options = .{
        //     .path = "/path/to/jetkv-cache.db",
        //     .truncate = false, // Set to `true` to clear the store on each server launch.
        //     .address_space_size = jetzig.jetkv.JetKV.FileBackend.addressSpace(4096),
        // },
    };

    /// SMTP configuration for Jetzig Mail. It is recommended to use a local SMTP relay,
    /// e.g.: https://github.com/juanluisbaptiste/docker-postfix
    ///
    /// Each configuration option can be overridden with environment variables:
    /// `JETZIG_SMTP_PORT`
    /// `JETZIG_SMTP_ENCRYPTION`
    /// `JETZIG_SMTP_HOST`
    /// `JETZIG_SMTP_USERNAME`
    /// `JETZIG_SMTP_PASSWORD`
    // pub const smtp: jetzig.mail.SMTPConfig = .{
    //     .port = 25,
    //     .encryption = .none, // .insecure, .none, .tls, .start_tls
    //     .host = "localhost",
    //     .username = null,
    //     .password = null,
    // };

    /// Force email delivery in development mode (instead of printing email body to logger).
    pub const force_development_email_delivery = false;
};

pub fn init(app: *jetzig.App) !void {
    _ = app;
    // Example custom route:
    // app.route(.GET, "/custom/:id/foo/bar", @import("app/views/custom/foo.zig"), .bar);
}

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = if (builtin.mode == .Debug) gpa.allocator() else std.heap.c_allocator;
    defer if (builtin.mode == .Debug) std.debug.assert(gpa.deinit() == .ok);

    var app = try jetzig.init(allocator);
    defer app.deinit();

    try app.start(routes, .{});
}
